package com.entmanage.quartz.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.entmanage.base.hrm.domain.HrmEmployee;
import com.entmanage.base.hrm.service.IHrmEmployeeService;
import com.entmanage.base.leave.domain.LeaveBalance;
import com.entmanage.base.leave.service.ILeaveBalanceService;
import com.entmanage.base.memo.domain.MemoReminder;
import com.entmanage.base.memo.mapper.MemoReminderMapper;
import com.entmanage.base.memo.service.impl.MemoReminderServiceImpl;
import com.entmanage.common.core.domain.entity.SysUser;
import com.entmanage.common.core.domain.model.LoginUser;
import com.entmanage.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import com.entmanage.common.utils.StringUtils;
import com.entmanage.base.memo.service.IMemoReminderService;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 定时任务调度测试
 * 
 * @author ruoyi
 */
@Component("ryTask")
public class RyTask
{
    private static final Logger log = LoggerFactory.getLogger(MemoReminderServiceImpl.class);

    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
    {
        System.out.println(StringUtils.format("执行多参方法： 字符串类型{}，布尔类型{}，长整型{}，浮点型{}，整形{}", s, b, l, d, i));
    }

    public void ryParams(String params)
    {
        System.out.println("执行有参方法：" + params);
    }

    public void ryNoParams()
    {
        System.out.println("执行无参方法");
    }

    @Autowired
    private MemoReminderMapper memoReminderMapper;

    @Autowired
    private IMemoReminderService memoReminderService;

    @Autowired
    private IHrmEmployeeService employeeService;

    @Autowired
    private ILeaveBalanceService leaveBalanceService;


    /**
     * 【核心定时任务】每5分钟检查一次，发送已到时间但未发送的提醒邮件
     */
    public void rySendEmail()
    {
        log.info("【定时任务】开始执行备忘录邮件提醒...");

        // 查询所有未发送且设置了提醒的备忘录
        List<MemoReminder> reminders = memoReminderMapper.selectMemoReminderList(new MemoReminder());

        // 获取今天日期（只比较年月日）
        Calendar today = Calendar.getInstance();
        today.set(Calendar.HOUR_OF_DAY, 0);
        today.set(Calendar.MINUTE, 0);
        today.set(Calendar.SECOND, 0);
        today.set(Calendar.MILLISECOND, 0);
        long todayStartMillis = today.getTimeInMillis();

        for (MemoReminder reminder : reminders) {
            Long id = reminder.getId();
            Date remindDate = reminder.getRemindTime();
            Integer isSent = reminder.getIsSent();
            String email = reminder.getRemindEmail();

            // 跳过已发送的
            if (isSent == 1) {
                continue;
            }

            // 必须有提醒日期、邮箱不为空
            if (remindDate == null ||
                    email == null ||
                    email.trim().isEmpty()) {
                continue;
            }

            // 提取 remindDate 的“日期部分”（年月日），忽略时分秒
            Calendar remindCal = Calendar.getInstance();
            remindCal.setTime(remindDate);
            remindCal.set(Calendar.HOUR_OF_DAY, 0);
            remindCal.set(Calendar.MINUTE, 0);
            remindCal.set(Calendar.SECOND, 0);
            remindCal.set(Calendar.MILLISECOND, 0);
            long remindDateMillis = remindCal.getTimeInMillis();

            // 判断：提醒时间的“日期”是否是今天？
            if (todayStartMillis == remindDateMillis) {
                log.info("📧 触发提醒：ID={}，标题=\"{}\"，将在今日发送邮件", id, reminder.getTitle());
                try {
                    // 调用异步发送方法
                    memoReminderService.sendReminderEmail(id);
                } catch (Exception e) {
                    // 使用 {} 格式化，避免不必要的字符串拼接
                    log.error("❌ 发送邮件失败：ID={}", id, e);
                }
            }
        }

        log.info("【定时任务】邮件提醒执行结束。");
    }


    /**
     * 生成【管理员】的提前通知提醒（如提前3天提醒HR准备生日福利）
     *
     * @param advanceDays 提前几天通知（如 3 表示生日前3天触发）
     * @param notifyEmails 管理员邮箱列表（如 hr@company.com, admin@company.com）
     */
    public void generateAdvanceNoticeForAdmins(int advanceDays, List<String> notifyEmails) {
        log.info("开始执行【管理员提前通知】任务，提前 {} 天发送，通知 {} 个邮箱",
                advanceDays, notifyEmails != null ? notifyEmails.size() : 0);

        if (notifyEmails == null || notifyEmails.isEmpty()) {
            log.warn("未配置管理员邮箱，跳过执行");
            return;
        }

        setupSystemUserContext(1L, 101L);

        LocalDate today = LocalDate.now();
        // 目标：advanceDays 天后的员工生日
        LocalDate targetBirthday = today.plusDays(advanceDays);
        log.info("今天是：{}，目标生日日期：{}（用于提前 {} 天通知）", today, targetBirthday, advanceDays);

        List<HrmEmployee> employees = employeeService.getEmployeesWithBirthdayOn(
                targetBirthday.getMonthValue(),
                targetBirthday.getDayOfMonth()
        );

        log.info("查询到 {} 名员工将在 {} 过生日，需提前 {} 天通知管理员", employees.size(), targetBirthday, advanceDays);

        if (employees.isEmpty()) {
            return;
        }

        // 构建提醒内容
        StringBuilder content = new StringBuilder();
        content.append("📅 生日提醒（提前 ").append(advanceDays).append(" 天）：\n\n");
        for (HrmEmployee emp : employees) {
            content.append("• ").append(emp.getEmpName())
                    .append("\n");
        }
        content.append("\n请提前准备生日福利/贺卡等。");

        // ✅ 设置提醒时间为：targetBirthday 当天的某个时间（如早上 9:00）
        LocalDateTime remindTime = LocalDateTime.of(
                targetBirthday.getYear(),
                targetBirthday.getMonth(),
                targetBirthday.getDayOfMonth(),
                9, 0
        );

        // 但我们要的是：**在今天（targetBirthday - advanceDays）触发发送**
        // 所以 remindTime 应该是：targetBirthday 减去 advanceDays
        // ✅ 关键：提前发送
        LocalDateTime actualRemindTime = remindTime.minusDays(advanceDays);


        // 唯一标识：避免重复生成
        String uniqueKey = "admin_birthday_notice_" +
                today.getYear() + "_" +
                advanceDays + "days";

        MemoReminder query = new MemoReminder();
        query.setMemoType("birthday_admin");
        query.setUniqueKey(uniqueKey);

        boolean exists = memoReminderService.existsReminder(query);
        if (exists) {
            log.debug("管理员提醒已存在，跳过生成：{}", uniqueKey);
            return;
        }

        MemoReminder reminder = new MemoReminder();
        // 系统任务
        reminder.setUserId(-1L);
        reminder.setDeptId(-1L);
        reminder.setTitle("🎂 提醒：以下员工将在 " + advanceDays + " 天后过生日");
        reminder.setContent(content.toString());
        reminder.setMemoType("birthday_admin");
        reminder.setRemindTime(Date.from(actualRemindTime.atZone(ZoneId.systemDefault()).toInstant()));
        // 管理员邮箱
        reminder.setRemindEmails(new ArrayList<>(notifyEmails));
        reminder.setAdvanceDays((long) advanceDays);
        reminder.setIsSent(0);
        reminder.setDelFlag(0);
        reminder.setUniqueKey(uniqueKey);

        try {
            memoReminderService.insertMemoReminder(reminder);
            log.info("✅ 已生成管理员提前 {} 天提醒，收件人：{}", advanceDays, notifyEmails);
        } catch (Exception e) {
            log.error("❌ 生成管理员提醒失败", e);
        }
    }

    /**
     * 生成【员工本人】的生日祝福提醒（生日当天发送）
     */
    public void generateBirthdayWishForEmployee() {
        log.info("开始执行【员工本人生日祝福】任务，将在生日当天发送");

        setupSystemUserContext(1L, 101L);

        LocalDate today = LocalDate.now();

        List<HrmEmployee> employees = employeeService.getEmployeesWithBirthdayOn(
                today.getMonthValue(),
                today.getDayOfMonth()
        );

        log.info("查询到 {} 名员工今天生日", employees.size());

        for (HrmEmployee emp : employees) {
            if (emp.getEmail() == null || emp.getEmail().trim().isEmpty()) {
                continue;
            }

            String uniqueKey = "birthday_wish_" + emp.getEmpId() + "_" + today.getYear();

            MemoReminder query = new MemoReminder();
            query.setUserId(emp.getEmpId());
            query.setMemoType("birthday");
            query.setUniqueKey(uniqueKey);

            if (memoReminderService.existsReminder(query)) {
                log.debug("员工 {} 的生日祝福已存在，跳过", emp.getEmpName());
                continue;
            }

            // 生日当天早上 8:00 发送
            LocalDateTime remindTime = LocalDateTime.of(today.getYear(), today.getMonth(), today.getDayOfMonth(), 8, 0);

            MemoReminder reminder = new MemoReminder();
            reminder.setUserId(emp.getEmpId());
            reminder.setDeptId(emp.getDeptId());
            reminder.setTitle("🎉 属于你的特别日子！");
            reminder.setContent(generateBirthdayContent(emp.getEmpName(), today));
            reminder.setMemoType("birthday");
            reminder.setRemindTime(Date.from(remindTime.atZone(ZoneId.systemDefault()).toInstant()));
            // 只发给本人
            reminder.setRemindEmails(Arrays.asList(emp.getEmail()));
            // 标记为当天发送
            reminder.setAdvanceDays(0L);
            reminder.setIsSent(0);
            reminder.setDelFlag(0);
            reminder.setUniqueKey(uniqueKey);

            try {
                memoReminderService.insertMemoReminder(reminder);
                log.info("✅ 已为员工 {} 生成生日祝福", emp.getEmpName());
            } catch (Exception e) {
                log.error("❌ 生成生日祝福失败：{}", emp.getEmpName(), e);
            }
        }
    }

    public void autoGenerateBirthdayReminders(Long userId, Long deptId) {
        if (userId == null || deptId == null) {
            log.error("❌ 执行失败：管理员 userId 或 deptId 为空");
            return;
        }

        log.info("🎂 开始生成生日提醒，执行人 userId={}, deptId={}", userId, deptId);

        // 设置安全上下文：让后续操作以该管理员身份执行
        setupSystemUserContext(userId, deptId);

        // 配置管理员邮箱
        List<String> adminEmails = Arrays.asList("1911708828@qq.com");

        try {
            // 1. 给今天过生日的员工发送祝福
            generateBirthdayWishForEmployee();

            // 2. 提前 3 天通知管理员
            generateAdvanceNoticeForAdmins(3, adminEmails);

            // 3. 提前 7 天通知管理员（可选）
            generateAdvanceNoticeForAdmins(7, adminEmails);

            log.info("✅ 生日提醒生成任务执行成功。");
        } catch (Exception e) {
            log.error("❌ 生日提醒任务执行异常", e);
        }
    }

    private String generateBirthdayContent(String name, LocalDate birthday) {
        String dateStr = birthday.getMonthValue() + "月" + birthday.getDayOfMonth() + "日";
        return "🎂 亲爱的 " + name + "：\n\n" +
                "今天（" + dateStr + "）就是你的生日啦！\n\n" +
                "感谢你一直以来的努力与付出，愿你在新的一岁里：\n" +
                "\n" +
                "• 身体健康，笑容常在\n" +
                "• 工作顺利，心想事成\n" +
                "• 生活美满，幸福安康\n" +
                "\n" +
                "行政部 / HR 敬上";
    }

    private void setupSystemUserContext(Long userId, Long deptId) {
        // 1. 创建 SysUser 对象
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setUserName("admin");
        sysUser.setNickName("系统管理员");
        sysUser.setDeptId(deptId);

        // 2. 创建权限集合
        Set<String> permissions = new HashSet<>(Arrays.asList("ROLE_SYSTEM", "ROLE_ADMIN"));

        // 3. 创建 LoginUser
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(userId);
        loginUser.setDeptId(deptId);
        loginUser.setPermissions(permissions);
        loginUser.setUser(sysUser);

        // 4. 创建 Authentication
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                loginUser,
                null,
                AuthorityUtils.createAuthorityList("ROLE_SYSTEM", "ROLE_ADMIN")
        );

        // 5. 设置上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        log.debug("✅ 安全上下文已设置：userId={}, deptId={}", userId, deptId);
    }

    /**
     * 定时同步员工状态到假期余额表：
     * - 新员工（status=0 且假期记录不存在）：自动创建假期记录
     * - 离职员工（status=1）：设置 del_flag=2
     * - 已删除员工（del_flag=2）：同步设置假期记录 del_flag=2
     */
    @Scheduled(cron = "0 0/10 * * * ?") // 每10分钟执行一次
    public void syncEmployeeLeaveBalance() {
        log.info("【定时任务】开始同步员工假期余额状态...");

        setupSystemUserContext(1L, 101L);

        try {
            // 1. 查询所有在职员工（status = 0 且未被删除）
            List<HrmEmployee> activeEmployees = employeeService.listByStatusAndDelFlag(0, 0);

            // 2. 查询所有离职员工（status = 1 且未被删除）
            List<HrmEmployee> resignedEmployees = employeeService.listByStatusAndDelFlag(1, 0);

            // 3. 查询所有已被逻辑删除的员工（del_flag = 2，无论 status 是多少）
            List<HrmEmployee> deletedEmployees = employeeService.listByDelFlag(2);

            // 4. 处理新员工：自动创建假期记录
            for (HrmEmployee emp : activeEmployees) {
                Long empId = emp.getEmpId();
                if (empId == null) {
                    continue;
                }

                List<LeaveBalance> existingList = leaveBalanceService.findByEmployeeIdAndDelFlagNot2(empId);
                if (existingList.isEmpty()) {
                    LeaveBalance balance = new LeaveBalance();
                    balance.setEmployeeId(empId);
                    balance.setUserId(emp.getUserId());
                    balance.setDeptId(emp.getDeptId());

                    Integer workYear = calculateWorkYear(emp.getProbationEnd());
                    balance.setWorkYear(workYear != null ? workYear.longValue() : 0L);

                    int annualLeaveDays = workYear == null || workYear < 1 ? 0 :
                            (workYear < 3 ? 2 : 5);
                    BigDecimal hours = BigDecimal.valueOf(annualLeaveDays * 8);
                    balance.setAnnualLeave(hours);
                    balance.setRemainingAnnualLeave(hours);

                    balance.setRemainingPersonalLeave(BigDecimal.ZERO);
                    balance.setRemainingSickLeave(BigDecimal.ZERO);
                    balance.setRemainingMarriageLeave(BigDecimal.ZERO);
                    balance.setRemainingMaternityLeave(BigDecimal.ZERO);
                    balance.setRemainingFaternityLeave(BigDecimal.ZERO);
                    balance.setRemainingOvertimeLeave(BigDecimal.ZERO);
                    balance.setRemainingOthersLeave(BigDecimal.ZERO);

                    balance.setDelFlag("0");
                    balance.setCreateTime(new Date());
                    balance.setCreateBy("system");

                    leaveBalanceService.save(balance);
                    log.info("✅ 为新员工 {} (ID={}) 自动创建假期记录", emp.getEmpName(), empId);
                }
            }

            // 5. 处理离职员工（status=1）：标记假期记录为删除
            processEmployeesToMarkLeaveAsDeleted(resignedEmployees, "离职");

            // 6. 处理已删除员工（del_flag=2）：同样标记假期记录为删除
            processEmployeesToMarkLeaveAsDeleted(deletedEmployees, "已删除");

            log.info("【定时任务】员工假期余额同步完成。");
        } catch (Exception e) {
            log.error("❌ 员工假期余额同步失败", e);
        }
    }

    /**
     * 通用方法：将指定员工的假期记录标记为 del_flag = "2"
     */
    private void processEmployeesToMarkLeaveAsDeleted(List<HrmEmployee> employees, String reason) {
        for (HrmEmployee emp : employees) {
            Long empId = emp.getEmpId();
            if (empId == null) {
                continue;
            }

            List<LeaveBalance> balances = leaveBalanceService.findByEmployeeIdAndDelFlagNot2(empId);
            for (LeaveBalance balance : balances) {
                balance.setDelFlag("2");
                balance.setUpdateTime(new Date());
                balance.setUpdateBy("system");
                leaveBalanceService.updateById(balance);
                log.info("🔒 员工 {} (ID={}) {}，假期记录标记为 del_flag=2", emp.getEmpName(), empId, reason);
            }
        }
    }

    /**
     * 根据试用期结束时间计算工作年限（整年）
     */
    private Integer calculateWorkYear(Date probationEndDate) {
        if (probationEndDate == null) {
            return 0;
        }
        LocalDate probationEnd = probationEndDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate now = LocalDate.now();
        if (now.isBefore(probationEnd)) {
            return 0;
        }
        return (int) java.time.temporal.ChronoUnit.YEARS.between(probationEnd, now);
    }
}
